
package com.studiofortress.sf.util.collections;

import com.studiofortress.sf.util.ArrayUtil;

/**
 * This represents a 1-dimensional array, similar to an ArrayList, but this
 * allows you to set a value at any index. The internal array will automatically
 * adjust to accomodate the indexes given. For example negative values are
 * allowed, and values far greater then the size of elements.
 *
 * Note that if you store just two values at -100 and another at 100, the array
 * will be produced to accomodate values to fill the entire range from -100 to
 * 100.
 * 
 * @author Joseph Lenton - JosephLenton@StudioFortress.com
 * @param <V> The value stored in this array.
 */
public class ResizableArray<V>
{
    private static final int DEFAULT_SIZE = 10;

    private int offset;
    private V[] vs;

    /**
     * Creates a resizable array which uses the default size of 10.
     */
    public ResizableArray()
    {
        this( DEFAULT_SIZE );
    }

    /**
     * Creates an array that is ready to store from 0 to startSize number of
     * elements.
     * @param startSize The number of elements for this array to be able to hold.
     */
    public ResizableArray(int startSize)
    {
        vs = (V[]) new Object[ startSize ];
    }
    
    /**
     * If the index is within bounds, then it returns the value stored at
     * that index. Otherwise it will return null if it's out of bounds.
     * @param index The index of the value to retrieve.
     * @return Null if there is no value stored at the index, otherwise the value stored at the index.
     */
    public V get(int index)
    {
        index += offset;

        if (index >= 0 && index < vs.length) {
            return vs[index];
        }

        return null;
    }

    /**
     * Sets the value at the given index to the given val.
     * @param index
     * @param val
     */
    public void set(int index, final V val)
    {
        index += offset;

        if (index < 0) {
            final int diff = -index;
            offset += diff;
            index += diff;

            // resize and copy
            final V[] newVs = (V[]) new Object[ vs.length + diff ];
            System.arraycopy( vs, 0, newVs, diff, newVs.length-diff );
            vs = newVs;
        } else if (index >= vs.length) {
            vs = ArrayUtil.copyOf( vs, index+1 );
        }

        vs[ index ] = val;
    }

    /**
     * Cleares this array of all it's elements.
     */
    public void clear()
    {
        vs = (V[]) new Object[ DEFAULT_SIZE ];
    }
}